/*******************************************************************************
  * 文件：OxygenSensor.h
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2021-01-20
  * 说明：氧气传感器驱动
*******************************************************************************/
#include "OxygenSensor.h"
#include "SensorCtrl.h"
#include "OS_Timer.h"
#include "ComFun.h"
#include "Hardware_IO.h"
#include "Debug.h"

static Timer_ts sOxygenSensorTimer;
static Bool bWrok;
/*******************************************************************************
  * 函数名：OxygenFrameCheck
  * 功  能：氧气传感器报文校验
  * 参  数：U8 au8DATA[]：数据地址
  * 	   U8 u8Len：数据长度
  * 返回值：合法报文地址或NULL
  * 说  明：无
*******************************************************************************/
static OxygenFrame_ts* OxygenFrameCheck(U8 au8DATA[],U8 u8Len)
{
	U8 u8Index;

	// 遍历所有数据
	for(u8Index = 0;u8Index < u8Len;u8Index++)
	{
		// 寻找帧头
		if(au8DATA[u8Index] == 0x80)
		{
			OxygenFrame_ts *psFrame = (OxygenFrame_ts *)(au8DATA+u8Index);

			// TRG不对
			if(psFrame->u8TRG != 0x8F)
			{
				// 继续遍历
				continue;
			}

			// SRC不对
			if(psFrame->u8SRC != 0xEA)
			{
				// 继续遍历
				continue;
			}

			// Len不对
			if(psFrame->u8LEN != 0x03)
			{
				// 继续遍历
				continue;
			}

			// SUM不对
			if(psFrame->u8CS != CheckSum(au8DATA+u8Index,7))
			{
				// 继续遍历
				continue;
			}

			// 校验合法，返回合法报文
			return psFrame;
		}
	}

	// 遍历完所有数据，仍未找到合法报文
    return NULL;
}

/*******************************************************************************
  * 函数名：OxygenSendHandshakeFrame
  * 功  能：氧气传感器发送握手报文
  * 参  数：无
  * 返回值：无
  * 说  明：底板上电后发送握手报文，握手成功后发送一条开始报文
*******************************************************************************/
static void OxygenSendHandshakeFrame(void)
{
	OxygenFrame_ts sSendFrame;

	sSendFrame.u8FMT = 0x80;
	sSendFrame.u8TRG = 0x8F;
	sSendFrame.u8SRC = 0xEA;
	sSendFrame.u8LEN = 0x03;
	sSendFrame.u8DATA1 = 0x01;
	sSendFrame.u8DATA2 = 0x00;
	sSendFrame.u8DATA3 = 0x00;
	sSendFrame.u8CS = 0xFD;

	// 发送握手报文
	SerialSendData(SERIAL_BOARD_OXYGEN_CHN,(U8 *)&sSendFrame,sizeof(sSendFrame));
}

/*******************************************************************************
  * 函数名：OxygenSendStartFrame
  * 功  能：氧气传感器发送启动报文
  * 参  数：无
  * 返回值：无
  * 说  明：底板上电后发送握手报文，握手成功后发送一条开始报文
*******************************************************************************/
static void OxygenSendStartFrame(void)
{
	OxygenFrame_ts sSendFrame;

	sSendFrame.u8FMT = 0x80;
	sSendFrame.u8TRG = 0x8F;
	sSendFrame.u8SRC = 0xEA;
	sSendFrame.u8LEN = 0x03;
	sSendFrame.u8DATA1 = 0x0D;
	sSendFrame.u8DATA2 = 0x00;
	sSendFrame.u8DATA3 = 0x00;
	sSendFrame.u8CS = 0x09;

	// 发送启动报文
	SerialSendData(SERIAL_BOARD_OXYGEN_CHN,(U8 *)&sSendFrame,sizeof(sSendFrame));
}

/*******************************************************************************
  * 函数名：OxygenFrameRecvTask
  * 功  能：氧气传感器报文解析任务
  * 参  数：无
  * 返回值：无
  * 说  明：解析成功报文后，缓存氧传感器浓度，停止定时发送初始化报文
*******************************************************************************/
static void OxygenFrameRecvTask(void)
{
	U8 au8RecvData[20];

    // 将数据从串口接收缓冲区取出
    U8 u8RecvLen = SerialRxFIFOPeek(SERIAL_BOARD_OXYGEN_CHN,au8RecvData,ARRAY_SIZE(au8RecvData));

    if(u8RecvLen != 0)
    {
    	// 数据校验
    	OxygenFrame_ts *psFrame = OxygenFrameCheck(au8RecvData,u8RecvLen);

		// 报文合法
    	if(psFrame != NULL)
    	{
    		if(psFrame->u8DATA1 == 0x01)
    		{
    			// 握手成功，停止发送握手
                DEBUG("Oxygen handshake success\r\n");
    			OS_TimerStop(&sOxygenSensorTimer);
    			// 发送启动报文
    			OxygenSendStartFrame();
                DEBUG("Oxygen start work\r\n");
    		}
    		else if(psFrame->u8DATA1 == 0x0D)
    		{
	    		// 保存氧气传感器浓度
	            Sensor_SetOxygenSensorVal((psFrame->u8DATA2 * 256 + psFrame->u8DATA3)/100);

                DEBUG("Oxygen: %d\r\n",(psFrame->u8DATA2 * 256 + psFrame->u8DATA3)/100);
    		}

    		// 清除已处理过的数据
            SerialRxFIFOClear(SERIAL_BOARD_OXYGEN_CHN,8 + ((U32)psFrame - (U32)au8RecvData));
    	}
    	else
    	{
    		// 非法数据过多，清除数据，防止堆积
    		if(u8RecvLen > 20)
    		{
    		    // 清空串口接收缓冲区，防止数据堆积
                SerialRxFIFOClear(SERIAL_BOARD_OXYGEN_CHN,u8RecvLen);
    		}
    	}
    }
}

/*******************************************************************************
  * 函数名：OxygenSensorInitHook_1S
  * 功  能：氧气传感器定时初始化函数
  * 参  数：无
  * 返回值：无
  * 说  明：定时1S发送握手报文，直到收到回复
*******************************************************************************/
static void OxygenSensorInitHook_1S(void)
{
	// 发送握手报文
	OxygenSendHandshakeFrame();

    DEBUG("Oxygen handshake\r\n");
}

/*******************************************************************************
  * 函数名：OxygenSensorIsWork
  * 功  能：检测氧气传感器是否正在工作
  * 参  数：无
  * 返回值：Bool：是否在工作
  * 说  明：无
*******************************************************************************/
Bool OxygenSensorIsWork(void)
{
	return bWrok;
}

/*******************************************************************************
  * 函数名：OxygenSensor_Stop
  * 功  能：氧气传感器暂停工作
  * 参  数：无
  * 返回值：无
  * 说  明：1.关闭电源 2.关闭定时器
*******************************************************************************/
void OxygenSensor_Stop(void)
{
	// 清除工作标志位
	bWrok = FALSE;
	// 关闭电源
	Hardware_Oxygen5VolCtrl(OFF);
    Hardware_Oxygen12VolCtrl(OFF);
	// 关闭定时器
	OS_TimerStop(&sOxygenSensorTimer);

    DEBUG("Oxygen close\r\n");
}


/*******************************************************************************
  * 函数名：OxygenSensor_Start
  * 功  能：氧气传感器启动工作
  * 参  数：无
  * 返回值：无
  * 说  明：1.开启电源 2.定时发送握手报文
*******************************************************************************/
void OxygenSensor_Start(void)
{
	// 启动工作标志位
	bWrok = TRUE;
	// 开启氧传感器电源
    Hardware_Oxygen5VolCtrl(ON);
    Hardware_Oxygen12VolCtrl(ON);
	// 开启氧传感器初始化定时器，定时1S发送握手报文
	OS_TimerStart(&sOxygenSensorTimer,u16SEC_TO_MSEC,OxygenSensorInitHook_1S);

    // 日志打印
    DEBUG("Oxygen init\r\n");
}

/*******************************************************************************
  * 函数名：OxygenSensor_Init
  * 功  能：氧气传感器初始化
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OxygenSensor_Init(void)
{
	bWrok = FALSE;
	// 初始化解析任务
	OS_TaskCreate(OxygenFrameRecvTask);
}

